package megadrum.gui;

import megadrum.*;
import megadrum.mididata.*;
import javax.swing.event.ChangeEvent;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JLabel;
import javax.swing.JSpinner;
import javax.swing.event.ChangeListener;

public class CustomCurvesEditor extends javax.swing.JDialog implements ActionListener, ChangeListener {

    public CustomCurvesEditor(MegadrumConfigTool mct) {
        super(mct, "Edit Custom Curves", false);
        parent = mct;
        initComponents();
        initComponents2();

        //repack the GUI
        pack();
    }

    private void initComponents2() {

        //curve selectors
        selectCurve1.addActionListener(this);
        selectCurve2.addActionListener(this);
        selectCurve3.addActionListener(this);
        selectCurve4.addActionListener(this);

        //points
        point = new JSpinner[9];
        point[0] = P1;
        point[1] = P2;
        point[2] = P3;
        point[3] = P4;
        point[4] = P5;
        point[5] = P6;
        point[6] = P7;
        point[7] = P8;
        point[8] = P9;
        for (int i = 0; i < 9; i++) {
            //set model
            point[i].setModel(new CustomSpinnerIntModel(Common.CURVE_PRESET[0][i], 2, 255, 1)); //default Linear curve
            point[i].setName("" + i); //this will allow us to know which point spinner has produced the ChangeEvent
            //set background color to white
            ((JSpinner.DefaultEditor) point[i].getEditor()).getTextField().setBackground(java.awt.Color.WHITE);
            ((JSpinner.DefaultEditor) point[i].getEditor()).getTextField().setForeground(java.awt.Color.BLACK);
            //add change listener
            point[i].addChangeListener(this);
            //add slider
            new PopupSlider(point[i]);
        }

        //curve panel
        curvePanel.add(new JLabel("<html>Select a curve by pressing any of the buttons above.<br>Then Load the desired curve with the selector below</html>", JLabel.CENTER), "Center");
        curveGraph = new CurveGraph[4];
        int[] curveNumbers = {0, 2, 6, 9}; //linear, log2, exp2, strong1
        for (int i = 0; i < 4; i++) {
            curveGraph[i] = new CurveGraph(point, curveNumbers[i]); //default Linear curve
        }

        //presets
        preset.setModel(new DefaultComboBoxModel(Common.CURVE_PRESET_NAMES));

        //buttons
        load.addActionListener(this);
        save.addActionListener(this);

    }

    //for each point spinner, if changed, update the curve graph
    public void stateChanged(ChangeEvent e) {
        JSpinner jsp = ((JSpinner) e.getSource());
        int p = Integer.parseInt(jsp.getName());
        curveGraph[currentCurve].setPoint(p, ((CustomSpinnerModel) jsp.getModel()).getIntValue());
    }

    //for the load/save buttons and for the curve selectors
    public void actionPerformed(ActionEvent ev) {
        Object o = ev.getSource();
        if (o == load) {
            if (preset.getSelectedIndex() == 0) { //<From MD> selected
                loadCurveFromMD();
            } else { //some Preset is selected
                loadPreset(preset.getSelectedIndex() - 1);
            }

        } else if (o == save) { //save current curve to megadrum
            saveCurveToMD();

        } else if (o == selectCurve1) {
            selectCurve1.setEnabled(false);
            selectCurve2.setEnabled(true);
            selectCurve3.setEnabled(true);
            selectCurve4.setEnabled(true);
            setTitle("Edit Custom Curve: 1");

            currentCurve = 0;
            showCurve(currentCurve);

        } else if (o == selectCurve2) {
            selectCurve1.setEnabled(true);
            selectCurve2.setEnabled(false);
            selectCurve3.setEnabled(true);
            selectCurve4.setEnabled(true);
            setTitle("Edit Custom Curve: 2");

            currentCurve = 1;
            showCurve(currentCurve);

        } else if (o == selectCurve3) {
            selectCurve1.setEnabled(true);
            selectCurve2.setEnabled(true);
            selectCurve3.setEnabled(false);
            selectCurve4.setEnabled(true);
            setTitle("Edit Custom Curve: 3");

            currentCurve = 2;
            showCurve(currentCurve);

        } else if (o == selectCurve4) {
            selectCurve1.setEnabled(true);
            selectCurve2.setEnabled(true);
            selectCurve3.setEnabled(true);
            selectCurve4.setEnabled(false);
            setTitle("Edit Custom Curve: 4");

            currentCurve = 3;
            showCurve(currentCurve);

        }
    }

    private void loadPreset(int selectedPreset) {
        for (int i = 0; i < 9; i++) {
            ((CustomSpinnerModel) point[i].getModel()).setIntValue(Common.CURVE_PRESET[selectedPreset][i]);
        }
    }

    private void loadCurveFromMD() {
        parent.loadCustomCurveFromMD(currentCurve);
    }

    public void convertSysexToData(byte[] sysex) {
        if (sysex.length == Common.LENGTH_CUSTOMCURVE) { //misc config sysex must be 24 bytes long
            switch (sysex[4]) {
                case 0:
                    actionPerformed(new ActionEvent(selectCurve1, 1001, "Curve 1"));
                    break;
                case 1:
                    actionPerformed(new ActionEvent(selectCurve2, 1001, "Curve 2"));
                    break;
                case 2:
                    actionPerformed(new ActionEvent(selectCurve3, 1001, "Curve 3"));
                    break;
                case 3:
                    actionPerformed(new ActionEvent(selectCurve4, 1001, "Curve 4"));
                    break;
            }
            for (int i = 0; i < 9; i++) {
                ((CustomSpinnerModel) point[i].getModel()).setIntValue(Converter.twoBytesToOneInt(sysex[5 + i * 2], sysex[6 + i * 2]));
            }
        }

    }

    private void saveCurveToMD() {
        byte[] tempByte;
        byte sysex[] = new byte[Common.LENGTH_CUSTOMCURVE];
        sysex[0] = Common.SYSEX_BEGIN;
        sysex[1] = Common.SYSEX_ID;
        sysex[2] = (byte) parent.getChainID();
        sysex[3] = Common.TYPE_CUSTOMCURVE;
        sysex[4] = (byte) currentCurve;
        for (int i = 0; i < 9; i++) {
            tempByte = Converter.intToTwoBytes(((CustomSpinnerModel) point[i].getModel()).getIntValue());
            sysex[5 + i * 2] = tempByte[0];
            sysex[6 + i * 2] = tempByte[1];
        }
        sysex[23] = Common.SYSEX_END;
        parent.sendCustomCurveToMD(sysex);
    }

    private void showCurve(int n) {
        curvePanel.removeAll();
        curvePanel.add(curveGraph[n], "Center");
        //update jspinners with points of the current curve
        for (int i = 0; i < 9; i++) {
            ((CustomSpinnerModel) point[i].getModel()).setIntValue( curveGraph[n].getPoint(i) );
        }
        curvePanel.updateUI();
    }

    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        load = new javax.swing.JButton();
        save = new javax.swing.JButton();
        javax.swing.JPanel jPanel1 = new javax.swing.JPanel();
        curvePanel = new javax.swing.JPanel();
        javax.swing.JLabel jLabel1 = new javax.swing.JLabel();
        preset = new javax.swing.JComboBox();
        javax.swing.JPanel jPanel3 = new javax.swing.JPanel();
        selectCurve1 = new javax.swing.JButton();
        selectCurve2 = new javax.swing.JButton();
        selectCurve3 = new javax.swing.JButton();
        selectCurve4 = new javax.swing.JButton();
        javax.swing.JPanel jPanel4 = new javax.swing.JPanel();
        P1 = new javax.swing.JSpinner();
        P2 = new javax.swing.JSpinner();
        P3 = new javax.swing.JSpinner();
        P4 = new javax.swing.JSpinner();
        P5 = new javax.swing.JSpinner();
        P6 = new javax.swing.JSpinner();
        P7 = new javax.swing.JSpinner();
        P8 = new javax.swing.JSpinner();
        P9 = new javax.swing.JSpinner();

        load.setText("Load");

        save.setText("Save this curve in MD");

        curvePanel.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0)));
        curvePanel.setPreferredSize(new java.awt.Dimension(302, 302));
        curvePanel.setLayout(new java.awt.BorderLayout());
        jPanel1.add(curvePanel);

        jLabel1.setText("Load curve:");

        selectCurve1.setText("Curve 1");
        jPanel3.add(selectCurve1);

        selectCurve2.setText("Curve 2");
        jPanel3.add(selectCurve2);

        selectCurve3.setText("Curve 3");
        jPanel3.add(selectCurve3);

        selectCurve4.setText("Curve 4");
        jPanel3.add(selectCurve4);

        jPanel4.setLayout(new java.awt.GridLayout(1, 9, 4, 0));
        jPanel4.add(P1);
        jPanel4.add(P2);
        jPanel4.add(P3);
        jPanel4.add(P4);
        jPanel4.add(P5);
        jPanel4.add(P6);
        jPanel4.add(P7);
        jPanel4.add(P8);
        jPanel4.add(P9);

        org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup()
                .addContainerGap()
                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING)
                    .add(org.jdesktop.layout.GroupLayout.LEADING, jPanel1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 534, Short.MAX_VALUE)
                    .add(org.jdesktop.layout.GroupLayout.LEADING, jPanel4, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 534, Short.MAX_VALUE)
                    .add(org.jdesktop.layout.GroupLayout.LEADING, layout.createSequentialGroup()
                        .add(jLabel1)
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                        .add(preset, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                        .add(load)
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED, 244, Short.MAX_VALUE)
                        .add(save))
                    .add(org.jdesktop.layout.GroupLayout.LEADING, jPanel3, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 534, Short.MAX_VALUE))
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(layout.createSequentialGroup()
                .addContainerGap()
                .add(jPanel3, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(jPanel1, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(jPanel4, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED, 13, Short.MAX_VALUE)
                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                    .add(save)
                    .add(jLabel1)
                    .add(preset, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                    .add(load))
                .addContainerGap())
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JSpinner P1;
    private javax.swing.JSpinner P2;
    private javax.swing.JSpinner P3;
    private javax.swing.JSpinner P4;
    private javax.swing.JSpinner P5;
    private javax.swing.JSpinner P6;
    private javax.swing.JSpinner P7;
    private javax.swing.JSpinner P8;
    private javax.swing.JSpinner P9;
    private javax.swing.JPanel curvePanel;
    private javax.swing.JButton load;
    private javax.swing.JComboBox preset;
    private javax.swing.JButton save;
    private javax.swing.JButton selectCurve1;
    private javax.swing.JButton selectCurve2;
    private javax.swing.JButton selectCurve3;
    private javax.swing.JButton selectCurve4;
    // End of variables declaration//GEN-END:variables
    private MegadrumConfigTool parent;
    private JSpinner[] point;
    private int currentCurve;
    private CurveGraph[] curveGraph;
}
